﻿/**
 * combo - jQuery jwwUI Copyright (c) 2013-2015 www.jeeww.com. All rights
 * reserved. Licensed under the GPL or commercial licenses
 */
(function($) {
	function setSize(target, sizeValue) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboObj = $.data(target, "combo").combo;
		var comboPanelObj = $.data(target, "combo").panel;
		var comboTextObj = comboObj.find("input.combo-text");
		var comboArrowObj = comboObj.find(".combo-arrow");
		var downArrowWidth = comboDefinations.hasDownArrow ? comboArrowObj._outerWidth() : 0;
		if (sizeValue && sizeValue != 'auto') {
			comboDefinations.width = sizeValue;
			comboObj._outerWidth(sizeValue);
		}
		var oWidth = comboObj._outerWidth();
		// comboTextObj._outerWidth(oWidth - downArrowWidth - 2);
		// var textWidth = (oWidth - downArrowWidth - 30) / oWidth;
		var textWidth = (oWidth - downArrowWidth - 3) / oWidth;
		textWidth = textWidth.toFixed(2) * 100;
		textWidth = textWidth + "%";
		comboTextObj.css({
		    width : textWidth,
		    height : comboObj.height() + "px",
		    lineHeight : comboObj.height() + "px"
		});
		comboArrowObj._outerHeight(comboObj.height());
		comboPanelObj.panel("resize", {
		    width : (comboDefinations.panelWidth ? comboDefinations.panelWidth : oWidth),
		    height : comboDefinations.panelHeight
		});
	}
	;
	function setArrowShowOrHide(target) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboObj = $.data(target, "combo").combo;
		if (comboDefinations.hasDownArrow) {
			comboObj.find(".combo-arrow").show();
		} else {
			comboObj.find(".combo-arrow").hide();
		}
	}
	;
	function createComboObj(target, definations) {
		$(target).addClass("combo-f").hide();
		var comboObj = null;
		if (definations.cusCls) {
			comboObj = $("<span class=\"combo\"></span>").addClass(definations.cusCls).insertAfter(target);
		} else {
			comboObj = $("<span class=\"combo\"></span>").insertAfter(target);
		}
		var comboTextObj = $("<input type=\"text\" class=\"combo-text\">").appendTo(comboObj);
		$("<span class=\"combo-arrow\"></span>").appendTo(comboObj);
		$("<input type=\"hidden\" class=\"combo-value\">").appendTo(comboObj);
		var comboPanelObj = $("<div class=\"combo-panel\"></div>").appendTo("body");
		comboPanelObj.panel({
		    doSize : false,
		    closed : true,
		    cls : "combo-p",
		    style : {
		        position : "absolute",
		        zIndex : 10
		    },
		    onOpen : function() {
			    $(this).panel("resize");
		    }
		});
		var comboPropertyName = $(target).attr("name");
		if (comboPropertyName) {
			comboObj.find("input.combo-value").attr("name", comboPropertyName);
			$(target).removeAttr("name").attr("comboName", comboPropertyName);
		}
		comboTextObj.attr("autocomplete", "off");
		return {
		    combo : comboObj,
		    panel : comboPanelObj
		};
	}
	;
	function destroy(target) {
		var comboTextObj = $.data(target, "combo").combo.find("input.combo-text");
		comboTextObj.inputbox("destroy");
		$.data(target, "combo").panel.panel("destroy");
		$.data(target, "combo").combo.remove();
		$(target).remove();
	}
	;
	function bindEvents(target) {
		var comboObj = $.data(target, "combo");
		var comboDefinations = comboObj.definations;
		var comboObjInner = $.data(target, "combo").combo;
		var comboPanel = $.data(target, "combo").panel;
		var comboText = comboObjInner.find(".combo-text");
		var comboArrow = comboObjInner.find(".combo-arrow");
		$(document).unbind(".combo").bind("mousedown.combo", function(e) {
			var p = $(e.target).closest("span.combo,div.combo-panel");
			if (p.length) {
				return;
			}
			var comboPanelObj = $("body>div.combo-p>div.combo-panel");
			comboPanelObj.panel("close");
		});
		comboObjInner.unbind(".combo");
		comboPanel.unbind(".combo");
		comboText.unbind(".combo");
		comboArrow.unbind(".combo");
		if (!comboDefinations.disabled) {
			comboText.bind("mousedown.combo", function(e) {
				$("div.combo-panel").not(comboPanel).panel("close");
				e.stopPropagation();
			}).bind("keydown.combo", function(e) {
				switch (e.keyCode) {
				case 38:
					comboDefinations.keyHandler.up.call(target);
					break;
				case 40:
					comboDefinations.keyHandler.down.call(target);
					break;
				case 13:
					e.preventDefault();
					comboDefinations.keyHandler.enter.call(target);
					return false;
				case 9:
				case 27:
					hidePanel(target);
					break;
				default:
					if (comboDefinations.editable) {
						if (comboObj.timer) {
							clearTimeout(comboObj.timer);
						}
						comboObj.timer = setTimeout(function() {
							var q = comboText.val();
							if (comboObj.previousValue != q) {
								comboObj.previousValue = q;
								$(target).combo("showPanel");
								comboDefinations.keyHandler.query.call(target, comboText.val());
								validate(target, true);
							}
						}, comboDefinations.delay);
					}
				}
			});
			comboArrow.bind("click.combo", function() {
				if (comboPanel.is(":visible")) {
					hidePanel(target);
				} else {
					$("div.combo-panel").panel("close");
					$(target).combo("showPanel");
				}
				comboText.focus();
			}).bind("mouseenter.combo", function() {
				$(this).addClass("combo-arrow-hover");
			}).bind("mouseleave.combo", function() {
				$(this).removeClass("combo-arrow-hover");
			}).bind("mousedown.combo", function() {
			});
			comboText.bind("click.combo", function() {
				if (comboPanel.is(":visible")) {
					hidePanel(target);
				} else {
					$("div.combo-panel").panel("close");
					$(target).combo("showPanel");
				}
				comboText.focus();
			}).bind("mouseenter.combo", function() {
				$(this).addClass("combo-arrow-hover");
			}).bind("mouseleave.combo", function() {
				$(this).removeClass("combo-arrow-hover");
			}).bind("mousedown.combo", function() {
			});
		}
	}
	;
	function showPanel(target) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboObj = $.data(target, "combo").combo;
		var comboPanel = $.data(target, "combo").panel;
		if ($.fn.window) {
			comboPanel.panel("panel").css("z-index", $.fn.window.defaults.zIndex++);
		}
		comboPanel.panel("move", {
		    left : comboObj.offset().left,
		    top : getTopPx()
		});
		if (comboPanel.panel("definations").closed) {
			comboPanel.panel("open");
			comboDefinations.onShowPanel.call(target);
		}
		(function() {
			if (comboPanel.is(":visible")) {
				comboPanel.panel("move", {
				    left : getLeftPx(),
				    top : getTopPx()
				});
				setTimeout(arguments.callee, 200);
			}
		})();
		function getLeftPx() {
			var leftWidth = comboObj.offset().left;
			if (leftWidth + comboPanel._outerWidth() > $(window)._outerWidth() + $(document).scrollLeft()) {
				leftWidth = $(window)._outerWidth() + $(document).scrollLeft() - comboPanel._outerWidth();
			}
			if (leftWidth < 0) {
				leftWidth = 0;
			}
			return leftWidth;
		}
		;
		function getTopPx() {
			var top = comboObj.offset().top + comboObj._outerHeight();
			if (top + comboPanel._outerHeight() > $(window)._outerHeight() + $(document).scrollTop()) {
				top = comboObj.offset().top - comboPanel._outerHeight();
			}
			if (top < $(document).scrollTop()) {
				top = comboObj.offset().top + comboObj._outerHeight();
			}
			return top;
		}
		;
	}
	;
	function hidePanel(target) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboPanelObj = $.data(target, "combo").panel;
		comboPanelObj.panel("close");
		comboDefinations.onHidePanel.call(target);
	}
	;
	function validate(target, validateFlag) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboObj = $.data(target, "combo").combo.find("input.combo-text");
		comboObj.inputbox(comboDefinations);
		if (validateFlag) {
			comboObj.inputbox("validate");
		}
	}
	;
	function setDisabled(target, flag) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboObj = $.data(target, "combo").combo;
		if (flag) {
			comboDefinations.disabled = true;
			$(target).attr("disabled", true);
			comboObj.find(".combo-value").attr("disabled", true);
			comboObj.find(".combo-text").attr("disabled", true);
		} else {
			comboDefinations.disabled = false;
			$(target).removeAttr("disabled");
			comboObj.find(".combo-value").removeAttr("disabled");
			comboObj.find(".combo-text").removeAttr("disabled");
		}
	}
	;
	function clear(target) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboObj = $.data(target, "combo").combo;
		if (comboDefinations.multiple) {
			comboObj.find("input.combo-value").remove();
		} else {
			comboObj.find("input.combo-value").val("");
		}
		comboObj.find("input.combo-text").val("");
	}
	;
	function getComboText(target) {
		var comboObj = $.data(target, "combo").combo;
		return comboObj.find("input.combo-text").val();
	}
	;
	function setComboText(target, textValue) {
		var comboObj = $.data(target, "combo").combo;
		comboObj.find("input.combo-text").val(textValue);
		validate(target, true);
		$.data(target, "combo").previousValue = textValue;
	}
	;
	function getComboValues(target) {
		var values = [];
		var comboObj = $.data(target, "combo").combo;
		comboObj.find("input.combo-value").each(function() {
			values.push($(this).val());
		});
		return values;
	}
	;
	function setComboValues(target, values) {
		var comboDefinations = $.data(target, "combo").definations;
		var comboNowValues = getComboValues(target);
		var comboObj = $.data(target, "combo").combo;
		comboObj.find("input.combo-value").remove();
		var comboPropertyName = $(target).attr("comboName");
		if (values) {
			if (!(values instanceof Array)) {
				values = values.split(",");
			}
		} else {
			return;
		}
		for ( var i = 0; i < values.length; i++) {
			var comboValueHidden = $("<input type=\"hidden\" class=\"combo-value\">").appendTo(comboObj);
			if (comboPropertyName) {
				comboValueHidden.attr("name", comboPropertyName);
			}
			comboValueHidden.val(values[i]);
		}
		var tmp = [];
		for ( var i = 0; i < comboNowValues.length; i++) {
			tmp[i] = comboNowValues[i];
		}
		var aa = [];
		for ( var i = 0; i < values.length; i++) {
			for ( var j = 0; j < tmp.length; j++) {
				if (values[i] == tmp[j]) {
					aa.push(values[i]);
					tmp.splice(j, 1);
					break;
				}
			}
		}
		if (aa.length != values.length || values.length != comboNowValues.length) {
			if (comboDefinations.multiple) {
				comboDefinations.onChange.call(target, values, comboNowValues);
			} else {
				comboDefinations.onChange.call(target, values[0], comboNowValues[0]);
			}
		}
	}
	;
	function getComboValue(comboObj) {
		var valueObjs = getComboValues(comboObj);
		return valueObjs[0];
	}
	;
	function setComboValue(comboObj, params) {
		setComboValues(comboObj, [ params ]);
	}
	;
	function comboOnChange(comboObj) {
		var comboDefinations = $.data(comboObj, "combo").definations;
		var fn = comboDefinations.onChange;
		comboDefinations.onChange = function() {
		};
		if (comboDefinations.multiple) {
			if (comboDefinations.value) {
				if (typeof comboDefinations.value == "object") {
					setComboValues(comboObj, comboDefinations.value);
				} else {
					setComboValue(comboObj, comboDefinations.value);
				}
			} else {
				setComboValues(comboObj, []);
			}
			comboDefinations.originalValue = getComboValues(comboObj);
		} else {
			setComboValue(comboObj, comboDefinations.value);
			comboDefinations.originalValue = comboDefinations.value;
		}
		comboDefinations.onChange = fn;
	}
	;
	$.fn.combo = function(definations, param) {
		if (typeof definations == "string") {
			return $.fn.combo.methods[definations](this, param);
		}
		definations = definations || {};
		return this.each(function() {
			var comboObj = $.data(this, "combo");
			if (comboObj) {
				$.extend(comboObj.definations, definations);
			} else {
				var newDefinations = $.extend({}, $.fn.combo.defaults, $.fn.combo.parseDefinations(this), definations);
				var r = createComboObj(this, newDefinations);
				comboObj = $.data(this, "combo", {
				    definations : newDefinations,
				    combo : r.combo,
				    panel : r.panel,
				    previousValue : null
				});
				$(this).removeAttr("disabled");
			}
			$("input.combo-text", comboObj.combo).attr("readonly", !comboObj.definations.editable);
			setArrowShowOrHide(this);
			setDisabled(this, comboObj.definations.disabled);
			setSize(this, comboObj.definations.width);
			bindEvents(this);
			validate(this);
			comboOnChange(this);
		});
	};
	$.fn.combo.methods = {
	    definations : function(jq) {
		    return $.data(jq[0], "combo").definations;
	    },
	    panel : function(jq) {
		    return $.data(jq[0], "combo").panel;
	    },
	    textbox : function(jq) {
		    return $.data(jq[0], "combo").combo.find("input.combo-text");
	    },
	    destroy : function(jq) {
		    return jq.each(function() {
			    destroy(this);
		    });
	    },
	    resize : function(jq, width) {
		    return jq.each(function() {
			    setSize(this, width);
		    });
	    },
	    showPanel : function(jq) {
		    return jq.each(function() {
			    showPanel(this);
		    });
	    },
	    hidePanel : function(jq) {
		    return jq.each(function() {
			    hidePanel(this);
		    });
	    },
	    disable : function(jq) {
		    return jq.each(function() {
			    setDisabled(this, true);
			    bindEvents(this);
		    });
	    },
	    enable : function(jq) {
		    return jq.each(function() {
			    setDisabled(this, false);
			    bindEvents(this);
		    });
	    },
	    validate : function(jq) {
		    return jq.each(function() {
			    validate(this, true);
		    });
	    },
	    isValid : function(jq) {
		    var comboTextObj = $.data(jq[0], "combo").combo.find("input.combo-text");
		    return comboTextObj.inputbox("isValid");
	    },
	    clear : function(jq) {
		    return jq.each(function() {
			    clear(this);
		    });
	    },
	    reset : function(jq) {
		    return jq.each(function() {
			    var comboDefinations = $.data(this, "combo").definations;
			    if (comboDefinations.multiple) {
				    $(this).combo("setValues", comboDefinations.originalValue);
			    } else {
				    $(this).combo("setValue", comboDefinations.originalValue);
			    }
		    });
	    },
	    getText : function(jq) {
		    return getComboText(jq[0]);
	    },
	    setText : function(jq, v) {
		    return jq.each(function() {
			    setComboText(this, v);
		    });
	    },
	    getValues : function(jq) {
		    return getComboValues(jq[0]);
	    },
	    setValues : function(jq, v) {
		    return jq.each(function() {
			    setComboValues(this, v);
		    });
	    },
	    getValue : function(jq) {
		    return getComboValue(jq[0]);
	    },
	    setValue : function(jq, v) {
		    return jq.each(function() {
			    setComboValue(this, v);
		    });
	    }
	};
	$.fn.combo.parseDefinations = function(target) {
		var t = $(target);
		return $.extend({}, $.fn.inputbox.parseDefinations(target), $.parser.parseDefinations(target, [ "width",
		        "height", "separator", {
		            panelWidth : "number",
		            editable : "boolean",
		            hasDownArrow : "boolean",
		            delay : "number"
		        } ]), {
		    panelHeight : (t.attr("panelHeight") == "auto" ? "auto" : parseInt(t.attr("panelHeight")) || undefined),
		    multiple : (t.attr("multiple") ? true : undefined),
		    disabled : (t.attr("disabled") ? true : undefined),
		    value : (t.val() || undefined)
		});
	};
	$.fn.combo.defaults = $.extend({}, $.fn.inputbox.defaults, {
	    cusCls : null,
	    width : "auto",
	    height : 22,
	    panelWidth : null,
	    panelHeight : 200,
	    multiple : false,
	    separator : ",",
	    editable : true,
	    disabled : false,
	    hasDownArrow : true,
	    value : "",
	    delay : 200,
	    keyHandler : {
	        up : function() {
	        },
	        down : function() {
	        },
	        enter : function() {
	        },
	        query : function(q) {
	        }
	    },
	    onShowPanel : function() {
	    },
	    onHidePanel : function() {
	    },
	    onChange : function(target, v) {
	    }
	});
})(jQuery);
